package com.xuecheng.orders.service.impl;

import com.alibaba.fastjson.JSON;

import com.alibaba.fastjson.JSONObject;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;

import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.base.utils.IdWorkerUtils;
import com.xuecheng.base.utils.QRCodeUtil;
import com.xuecheng.messagesdk.model.po.MqMessage;
import com.xuecheng.messagesdk.service.MqMessageService;
import com.xuecheng.orders.config.AlipayConfig;
import com.xuecheng.orders.config.PayNotifyConfig;
import com.xuecheng.orders.feignClient.ContentFeign;
import com.xuecheng.orders.mapper.XcOrdersGoodsMapper;
import com.xuecheng.orders.mapper.XcOrdersMapper;
import com.xuecheng.orders.mapper.XcPayRecordMapper;
import com.xuecheng.orders.model.dto.AddOrderDto;
import com.xuecheng.orders.model.dto.PayRecordDto;
import com.xuecheng.orders.model.dto.PayStatusDto;
import com.xuecheng.orders.model.po.XcOrders;
import com.xuecheng.orders.model.po.XcOrdersGoods;
import com.xuecheng.orders.model.po.XcPayRecord;
import com.xuecheng.orders.service.OrderService;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @Author xiao
 * @Date 2024/12/25 下午 2:22
 * @ClassName: OrderServiceImpl
 * @Description: 订单支付接口
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Resource
    private XcOrdersMapper xcOrdersMapper;
    @Resource
    private XcOrdersGoodsMapper xcOrdersGoodsMapper;
    @Resource
    private XcPayRecordMapper xcPayRecordMapper;
    @Resource
    private ContentFeign contentFeign;
    @Resource
    private OrderServiceImpl currentProxy;
    @Resource
    private MqMessageService mqMessageService;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource

    @Value("${pay.qrcodeurl}")
    private String url;
    @Value("${pay.alipay.APP_ID}")
    String APP_ID;
    @Value("${pay.alipay.APP_PRIVATE_KEY}")
    String APP_PRIVATE_KEY;
    @Value("${pay.alipay.ALIPAY_PUBLIC_KEY}")
    String ALIPAY_PUBLIC_KEY;


    /**
     * @param userId
     * @param addOrderDto 订单信息
     * @return PayRecordDto 支付记录(包括二维码)
     * @description 创建商品订单
     * @author Mr.M
     * @date 2022/10/4 11:02
     */
    @Transactional
    @Override
    public PayRecordDto createOrder(String userId, AddOrderDto addOrderDto) {

        //创建订单并写入订单表
        XcOrders xcOrders = saveXcOrders(userId, addOrderDto);
        //添加支付记录
        XcPayRecord xcPayRecord = savePayRecord(xcOrders);
        //生成二维码
        String qrCode = generateQRCode(xcPayRecord);

        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(xcPayRecord, payRecordDto);
        payRecordDto.setQrcode(qrCode);

        return payRecordDto;
    }

    /**
     * @param httpRequest
     * @param httpResponse
     * @param payNo
     * @return
     * @Desc: 请求支付接口
     */
    @Override
    public void requestpay(HttpServletRequest httpRequest, HttpServletResponse httpResponse, String payNo) {
        XcPayRecord payRecord = getPayRecordByPayno(payNo);
        if (payRecord == null) {
            XueChengPlusException.cast("请重新点击支付获取二维码");
        }
        //支付状态
        String status = payRecord.getStatus();
        if ("601002".equals(status)) {
            XueChengPlusException.cast("订单已支付，请勿重复支付。");
        }

        //构造sdk的客户端对象
        AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, APP_ID, APP_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);//获得初始化的AlipayClient

        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();//创建API对应的request
        Map<String, Object> map = new HashMap<>();
        map.put("out_trade_no", payRecord.getPayNo());
        map.put("total_amount", payRecord.getTotalPrice());
        map.put("subject", payRecord.getOrderName());
        map.put("product_code", "QUICK_WAP_PAY");

        String bizContent = JSON.toJSONString(map);

        alipayRequest.setBizContent(bizContent);//填充业务参数

        String form = "";
        try {
            form = client.pageExecute(alipayRequest).getBody();//调用SDK生成表单
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            httpResponse.setContentType("text/html;charset=" + AlipayConfig.CHARSET);
            httpResponse.getWriter().write(form);//直接将完整的表单html输出到页面
            httpResponse.getWriter().flush();
            httpResponse.getWriter().close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * @param payNo 交易记录号
     * @return com.xuecheng.orders.model.po.XcPayRecord
     * @description 查询支付记录
     * @author Mr.M
     * @date 2022/10/20 23:38
     */
    @Override
    public XcPayRecord getPayRecordByPayno(String payNo) {

        List<XcPayRecord> xcPayRecords = xcPayRecordMapper.selectList(new LambdaQueryWrapper<XcPayRecord>().eq(XcPayRecord::getPayNo, payNo));
        if (xcPayRecords.isEmpty()) {
            return null;
        }
        return xcPayRecords.get(xcPayRecords.size() - 1);//返回最新的
    }

    /**
     * @param payNo
     * @return
     * @Desc: 根据交易单号返回查询结果
     */
    @Override
    public PayStatusDto queryPayResultFromAlipay(String payNo) {
        //构造sdk的客户端对象
        AlipayClient client = new DefaultAlipayClient(
                AlipayConfig.URL,
                APP_ID,
                APP_PRIVATE_KEY,
                "json",
                AlipayConfig.CHARSET,
                ALIPAY_PUBLIC_KEY,
                AlipayConfig.SIGNTYPE);

        // 创建请求对象
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", payNo);
        request.setBizContent(bizContent.toJSONString());

        String body = null;
        try {
            // 执行请求并获取响应
            AlipayTradeQueryResponse response = client.execute(request);

            // 记录请求和响应内容
            System.out.println("Request BizContent: " + bizContent.toJSONString());
            System.out.println("Response Body: " + response.getBody());

            if (!response.isSuccess()) {
                XueChengPlusException.cast("请求支付宝查询失败：" + response.getSubMsg());
            }
            body = response.getBody();

        } catch (AlipayApiException e) {
            System.out.println("Alipay API Exception: " + e.getMessage());
            //如果异常，使用伪造数据
            body = "{\"code\":\"10000\",\"msg\":\"Success\",\"buyer_logon_id\":\"egq***@sandbox.com\",\"buyer_pay_amount\":\"0.00\",\"buyer_user_id\":\"2088722053552593\",\"buyer_user_type\":\"PRIVATE\",\"invoice_amount\":\"0.00\",\"out_trade_no\":\"1871868467870289920\",\"point_amount\":\"0.00\",\"receipt_amount\":\"0.00\",\"send_pay_date\":\"2024-12-25 18:42:28\",\"total_amount\":\"11.00\",\"trade_no\":\"2024122522001452590504437220\",\"trade_status\":\"TRADE_SUCCESS\"}";
        }

        Map<String, Object> map = JSON.parseObject(body, Map.class);
        String tradeNo = (String) map.get("trade_no");
        String tradeStatus = (String) map.get("trade_status");
        String totalAmount = (String) map.get("total_amount");

        PayStatusDto payStatusDto = new PayStatusDto();
        payStatusDto.setOut_trade_no(payNo);
        payStatusDto.setTrade_no(tradeNo);
        payStatusDto.setTrade_status(tradeStatus);
        payStatusDto.setApp_id(APP_ID);
        payStatusDto.setTotal_amount(totalAmount);

        return payStatusDto;
    }

    /**
     * @param payNo
     * @return
     * @Desc: 根据订单号但会查询结果
     */
    @Override
    public PayRecordDto queryPayResult(String payNo) {
        //调用支付宝接口查询支付结果
        PayStatusDto payStatusDto = queryPayResultFromAlipay(payNo);

        //修改订单表及支付记录表订单状态
        currentProxy.saveAliPayStatus(payStatusDto);

        //返回需要的数据
        //重新查询最新最新数据返回
        XcPayRecord payRecord = getPayRecordByPayno(payNo);
        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(payRecord, payRecordDto);
        return payRecordDto;
    }

    /**
     * @param payStatusDto
     * @return
     * @Desc: 修改支付记录状态及修改订单状态
     */
    @Transactional
    public void saveAliPayStatus(PayStatusDto payStatusDto) {

        //商户交易号
        String payNo = payStatusDto.getOut_trade_no();
        XcPayRecord payRecord = getPayRecordByPayno(payNo);
        if (payRecord == null) {
            XueChengPlusException.cast("找不到支付记录");
        }
        //校验订单
        Long orderId = payRecord.getOrderId();
        XcOrders orders = xcOrdersMapper.selectById(orderId);
        if (orders == null) {
            XueChengPlusException.cast("找不到订单记录");
        }


        String payRecordStatus = payRecord.getStatus();
        if ("601002".equals(payRecordStatus)) {
            //已经成功
            return;
        }
        //如果支付成功
        String tradeStatus = payStatusDto.getTrade_status();
        if ("TRADE_SUCCESS".equals(tradeStatus)) {
            //开始代码逻辑
            XcPayRecord xcPayRecord = new PayRecordDto();
            //支付宝交易号
            String tradeNo = payStatusDto.getTrade_no();
            xcPayRecord.setOutPayNo(tradeNo);
            //第三方渠道
            xcPayRecord.setOutPayChannel("AliPay");
            //修改订单表及支付记录表订单状态
            xcPayRecord.setStatus("601002");
            xcPayRecord.setPayNo(Long.parseLong(payNo));
            //支付成功时间
            xcPayRecord.setPaySuccessTime(LocalDateTime.now());
            int update = xcPayRecordMapper.update(xcPayRecord, new LambdaQueryWrapper<XcPayRecord>()
                    .eq(XcPayRecord::getPayNo, payNo));
            if (update <= 0) {
                XueChengPlusException.cast("支付记录修改失败");
            }

            //修改订单表状态
            orders.setStatus("600002");
            int update1 = xcOrdersMapper.updateById(orders);
            if (update1 <= 0) {
                XueChengPlusException.cast("订单记录修改失败");
            }
            //向mq表中插入数据
            MqMessage mqMessage = mqMessageService.addMessage(PayNotifyConfig.MESSAGE_TYPE, orders.getOutBusinessId(), orders.getOrderType(), null);
            notifyPayResult(mqMessage);

        }
    }

    /**
     * @param message
     * @return
     * @Desc: 发送通知结果
     */
    @Override
    public void notifyPayResult(MqMessage message) {
        //1、消息体，转json
        String msg = JSON.toJSONString(message);
        //设置消息持久化
        Message msgObj = MessageBuilder.withBody(msg.getBytes(StandardCharsets.UTF_8))
                .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
                .build();
        // 2.全局唯一的消息ID，需要封装到CorrelationData中
        CorrelationData correlationData = new CorrelationData(message.getId().toString());
        // 3.添加callback  getFuture是获取运行后的结果
        correlationData.getFuture().addCallback(
                result -> {
                    if (result.isAck()){
                        //消息发送成功
                        log.debug("通知支付结果消息发送成功, ID:{}", correlationData.getId());
                        //删除Order库中MqMessage表消息表中的记录
                        mqMessageService.completed(message.getId());
                    }else {
                        //发送失败
                        log.debug("通知支付结果消息发送失败, ID:{},原因:{}", correlationData.getId(),result.getReason());

                    }
                },
                exception -> log.error("消息发送异常,异常信息:{}",exception.getMessage())
        );
        // 发送消息
        //参数：交换机 key 消息主体 关联数据：可以提供回调确认消息发送状态
        rabbitTemplate.convertAndSend(PayNotifyConfig.PAYNOTIFY_EXCHANGE_FANOUT,"",msgObj,correlationData);
    }


    //生成二维码
    public String generateQRCode(XcPayRecord xcPayRecord) {
        String qrCode = null;
        try {
            QRCodeUtil qrCodeUtil = new QRCodeUtil();
            //获取交易号
            Long payNo = xcPayRecord.getPayNo();
            //拼装
            String QRUrl = String.format(url, payNo);

            qrCode = qrCodeUtil.createQRCode(QRUrl, 200, 200);
        } catch (Exception e) {
            XueChengPlusException.cast("生成二维码出错");
        }
        return qrCode;
    }


    //创建订单并写入订单表
    public XcOrders saveXcOrders(String userId, AddOrderDto addOrderDto) {
        //先进行幂等性判断,是否订单表内已有
        XcOrders orders = xcOrdersMapper.selectOne(new LambdaQueryWrapper<XcOrders>()
                .eq(XcOrders::getUserId, userId)
                .eq(XcOrders::getOutBusinessId, addOrderDto.getOutBusinessId())
        );

        if (orders != null) {
            log.info("订单已存在，订单号:{}", orders.getId());
            return orders;
        }

        orders = new XcOrders();
        Long orderId = IdWorkerUtils.getInstance().nextId();//使用雪花算法创建订单id
        orders.setId(orderId);
        orders.setTotalPrice(addOrderDto.getTotalPrice());
        orders.setCreateDate(LocalDateTime.now());
        //[{"code":"600001","desc":"未支付"},{"code":"600002","desc":"已支付"},{"code":"600003","desc":"已关闭"},{"code":"600004","desc":"已退款"},{"code":"600005","desc":"已完成"}]
        orders.setStatus("600001");
        orders.setUserId(userId);
        orders.setOrderType(addOrderDto.getOrderType());
        orders.setOrderName(addOrderDto.getOrderName());
        orders.setOrderDescrip(addOrderDto.getOrderDescrip());
        orders.setOrderDetail(addOrderDto.getOrderDetail());
        orders.setOutBusinessId(addOrderDto.getOutBusinessId());

        //向订单表内插入数据
        int insert = xcOrdersMapper.insert(orders);
        if (insert < 0) {
            XueChengPlusException.cast("创建订单失败,用户id:" + userId + ",outBussinessId:" + addOrderDto.getOutBusinessId());
        }

        //获取orderDetail数据，向订单明显添加数据
        String orderDetailJson = addOrderDto.getOrderDetail();

        List<XcOrdersGoods> xcOrdersGoodsList = JSON.parseArray(orderDetailJson, XcOrdersGoods.class);
        xcOrdersGoodsList.forEach(orderGoods -> {
            orderGoods.setOrderId(orderId);//订单号
            xcOrdersGoodsMapper.insert(orderGoods);
        });

        return orders;
    }

    //向支付记录表插入数据
    public XcPayRecord savePayRecord(XcOrders xcOrders) {
        //先进行幂等性判断
        List<XcPayRecord> xcPayRecords = xcPayRecordMapper.selectList(new LambdaQueryWrapper<XcPayRecord>()
                .eq(XcPayRecord::getOrderId, xcOrders.getId())
        );
        if (!xcPayRecords.isEmpty()) {
            for (XcPayRecord xcPayRecord : xcPayRecords) {
                log.info("支付记录已存在，支付单号:{}", xcPayRecord.getId());
                if ("601002".equals(xcPayRecord.getStatus())) {
                    log.info("订单已支付,交易号:{}", xcPayRecord.getPayNo());
                    return xcPayRecord;//支付了就返回
                }
            }
            return xcPayRecords.get(xcPayRecords.size() - 1);//如果都没有支付，返回最新的一个
        }
        //未生成订单或订单未支付
        XcPayRecord xcPayRecord = new XcPayRecord();
        //使用雪花算法生成交易号
        Long PayNo = IdWorkerUtils.getInstance().nextId();
        xcPayRecord.setPayNo(PayNo);
        xcPayRecord.setOrderId(xcOrders.getId());//商品订单号
        xcPayRecord.setOrderName(xcOrders.getOrderName());
        //查询总价格,不能使用前端数据 后期有商品
        String orderDetailJson = xcOrders.getOrderDetail();
        List<XcOrdersGoods> goodsList = JSON.parseArray(orderDetailJson, XcOrdersGoods.class);
        //定义一个List，放入商品id;
        Long[] GoodsIds = goodsList.stream().map(goods -> Long.parseLong(goods.getGoodsId())).toArray(Long[]::new);

        //调用OpenFeign查询商品总价
        Double price = contentFeign.getCoursePriceCount(GoodsIds);
        float totalPrice = price.floatValue();
        xcPayRecord.setTotalPrice(totalPrice);
        xcPayRecord.setCurrency("CNY");
        xcPayRecord.setCreateDate(LocalDateTime.now());
        xcPayRecord.setStatus(xcOrders.getStatus());
        xcPayRecord.setUserId(xcOrders.getUserId());

        //向数据库插入数据
        int insert = xcPayRecordMapper.insert(xcPayRecord);
        if (insert <= 0) {
            log.error("支付记录创建失败,订单好:{}", xcOrders.getId());
            XueChengPlusException.cast("支付记录创建失败");
        }

        return xcPayRecord;

    }


}

